<!DOCTYPE html>
<html lang="en" >
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
    <meta name="viewport" content="width=device-width, initial-scale=1" />
    <meta name="author" content="GoJun" />
	
	
	
	<title>终极 Apk 瘦身优化 ｜ GoJun</title>
	
    
    
    <meta name="description" content="前言 Apk 随着我们开发迭代逐渐的增大，越来越臃肿肥大，在下载安装过程中，它们耗费的流量会越多，安装等待时间也会越长，这就意味着下载转化率越低，进而影响到广告效果。 因此 Apk 瘦身是优化的重要一部分，开发有必要定" />
    

    
    
    <meta name="keywords" content="Hugo, theme, zozo" />
    

	
    
    <link rel="shortcut icon" href="https://gojun.me/images/favicon.ico" />

    <link rel="stylesheet" type="text/css" media="screen" href="https://gojun.mecss/normalize.css" />
    <link rel="stylesheet" type="text/css" media="screen" href="https://cdn.jsdelivr.net/npm/animate.css@4.1.0/animate.min.css" />
    <link rel="stylesheet" type="text/css" media="screen" href="https://gojun.me/css/zozo.css" />
	<link rel="stylesheet" type="text/css" media="screen" href="https://cdn.jsdelivr.net/npm/remixicon@2.5.0/fonts/remixicon.css" />
    <link rel="stylesheet" type="text/css" media="screen" href="https://gojun.me/css/highlight.css" />

    
    
</head>

<body>
    <div class="main animate__animated animate__fadeInDown">
        <div class="nav_container animated fadeInDown">
    <div class="site_nav" id="site_nav">
        <ul>
            
            <li>
                <a href="/">Home</a>
            </li>
            
            <li>
                <a href="/posts/">Archive</a>
            </li>
            
            <li>
                <a href="/tags/">Tags</a>
            </li>
            
            <li>
                <a href="/projects/">Projects</a>
            </li>
            
        </ul>
    </div>
    <div class="menu_icon">
        <a id="menu_icon"><i class="ri-menu-line"></i></a>
    </div>
</div>
        <div class="header animated fadeInDown">
    <div class="site_title_container">
        <div class="site_title">
            <h1>
                <a href="https://gojun.me">
                    <span>GoJun</span>
                </a>
            </h1>
        </div>
        <div class="description">
            <p class="sub_title">为向往生活努力奋斗！</p>
            <div class="my_socials">
                
                
                <a href="https://github.com/freelander" title="github" target="_blank"><i class="ri-github-fill"></i></a>
                
                
                <a href="https://gojun.me/index.xml" type="application/rss+xml" title="rss" target="_blank"><i
                        class="ri-rss-fill"></i></a>
            </div>
        </div>
    </div>
</div>
        <div class="content">
            <div class="post_page">
                <div class="post animate__animated animate__fadeInDown">
                    <div class="post_title post_detail_title">
                        <h2><a href='/posts/android-reduce-apk-size/'>终极 Apk 瘦身优化</a></h2>
                        <span class="date">2019.09.10</span>
                    </div>
                    <div class="post_content markdown"><h1 id="前言">前言</h1>
<p>Apk 随着我们开发迭代逐渐的增大，越来越臃肿肥大，在下载安装过程中，它们耗费的流量会越多，安装等待时间也会越长，这就意味着下载转化率越低，进而影响到广告效果。</p>
<p>因此 Apk 瘦身是优化的重要一部分，开发有必要定期对 Apk 进行瘦身优化。</p>
<h1 id="分析">分析</h1>
<p>使用 Android Studio Analyze APK 进行分析，首先构建出一个 release 包，然后拖到 AS 开始分析。</p>
<p>

<div class="fancybox">
<a data-fancybox="demo" href="/images/2019/09/01.png">
<img src="/images/2019/09/01.png" alt="image"  />
</a>
</div>

</p>
<p>从上图分析结果，可以明显看出 Apk 的大小主要是 So 文件以及资源文件占据。</p>
<h1 id="开始瘦身">开始瘦身</h1>
<h2 id="apk-瘦身之-so-文件">Apk 瘦身之 So 文件</h2>
<p>还没有了解 So 文件的同学，可以看看这篇文章 <a href="http://allenfeng.com/2016/11/06/what-you-should-know-about-android-abi-and-so/">地址</a>。</p>
<p>再看看这篇文章 <a href="https://www.cnblogs.com/didikee/p/6683415.html">地址</a>，采集了市场主流多款 App 进行分析。</p>
<table>
<thead>
<tr>
<th>指令集</th>
<th>厂商</th>
<th>位数</th>
<th>描述</th>
</tr>
</thead>
<tbody>
<tr>
<td>arm64-v8a</td>
<td>ARM</td>
<td>64</td>
<td>第 8 代，64 位 ARM 处理器，很少设备，如：三星 Galaxy S6、华为 Mate 8</td>
</tr>
<tr>
<td>armeabi-v7a</td>
<td>ARM</td>
<td>32</td>
<td>第 7 代及以上的 ARM 处理器。2011 年以后，大部分的生产的 Android 设备都使用它（目前主流）</td>
</tr>
<tr>
<td>armeabi</td>
<td>ARM</td>
<td>32</td>
<td>第 5、6 代的 ARM 处理器，早期的手机使用的比较多</td>
</tr>
<tr>
<td>x86</td>
<td>Intel</td>
<td>32</td>
<td>平板、模拟器（x86设备也支持armeabi-v7a和armeabi）</td>
</tr>
<tr>
<td>x86_64</td>
<td>Intel</td>
<td>64</td>
<td>64位的平板</td>
</tr>
</tbody>
</table>
<p>通过上面查找到的资料，综合评估了下，决定项目只保留 armeabi-v7a 格式的 So 文件。</p>
<p>修改主工程 build.gradle 下的 abiFilters：</p>
<div class="highlight"><pre class="chroma"><code class="language-fallback" data-lang="fallback">android {
    // Some other configuration here...
    defaultConfig {
        ndk {
            abiFilters &#39;armeabi-v7a&#39;
        }
    }
}
</code></pre></div><h2 id="apk-瘦身之资源">Apk 瘦身之资源</h2>
<h3 id="移除无用的资源文件"><strong>移除无用的资源文件</strong></h3>
<p>随着版本迭代，会产生很多一些无用资源，<code>虽然在 build.gradle 中设置 shrinkResources 为 true 后，每次打包的时候就会自动排除无用的资源。但好像如果一些没用的代码对某个资源引用，貌似不会被移除</code>。</p>
<p>Android Studio 提供了一键清除无用资源文件功能</p>
<blockquote>
<p>在项目 app 文件下右键，Refactor &ndash;&gt; Remove Unused Resources..</p>
</blockquote>
<p>

<div class="fancybox">
<a data-fancybox="demo" href="/images/2019/09/02.png">
<img src="/images/2019/09/02.png" alt="image"  />
</a>
</div>

</p>
<p>我尝试勾选 <code>Delete unused @id declarations too</code> 发现布局有使用的 id 被检查到没有使用，因此我建议不要勾选这个选项。</p>
<p>为了安全建议大家执行操作前先 Preivew 下。</p>
<p>单独对某个文件夹下的资源进行检查方法：</p>
<blockquote>
<p>将光标定位在检查的文件夹 &ndash;&gt; Analyze &ndash;&gt; Run Inspection by name &ndash;&gt; unused resource</p>
</blockquote>
<p>

<div class="fancybox">
<a data-fancybox="demo" href="/images/2019/09/03.png">
<img src="/images/2019/09/03.png" alt="image"  />
</a>
</div>

</p>
<p><code>在检查的时候，发现没有检查出未使用的图片资源，但是有些图片确实是没有使用，尝试了好几次，最后发现原来是我自定义的 lint 配置，禁止检查 UnusedResources 资源了，因此在使用此功能时先注释掉原来自定义的 lint 规则。</code></p>
<div class="highlight"><pre class="chroma"><code class="language-fallback" data-lang="fallback">lintOptions {
        lintConfig file(&#34;gen/bgquality/lint/lint.xml&#34;)
        disable &#39;UnusedResources&#39;
    }
</code></pre></div><p><code>使用 Lint 工具检查</code></p>
<p>详细使用介绍可看这篇文章 <a href="https://juejin.im/entry/586f7ec1ac502e006c0c2070#android-studio-%E4%B8%AD%E4%BD%BF%E7%94%A8-lint">地址</a></p>
<h3 id="压缩图片资源"><strong>压缩图片资源</strong></h3>
<p>有些设计师从 PS 导出图后就直接发给开发了，因此需要我们自己压缩一次。推荐使用一个简单实用压缩工具 <a href="https://tinypng.com/">Tinypng</a>。</p>
<p>另外有一个比较专业压缩工具 <a href="https://squoosh.app/">Squoosh</a>，该工具是 Google 推出的一款免费开源图片压缩工具，有很多可定制化功能，例如图片尺寸调整、压缩比例调整、图片格式调整等等，如果你对压缩图片有比较多要求的时候，可选择这个工具。</p>
<h3 id="使用-webp-图片"><strong>使用 WebP 图片</strong></h3>
<p>可以到知乎看下这篇文章 <a href="https://www.zhihu.com/question/27201061">WebP 相对于 PNG、JPG 有什么优势？</a></p>
<p><code>需要注意：</code></p>
<blockquote>
<p>Android 从 4.0 才开始 WebP 的原生支持，意味着要兼容 4.0 以下机型需要添加适配库；当然现在市面上适配 4.0 以下的应用已经很少了。
Android 4.2.1+ 才支持显示含透明度的 WebP，因此最低版本小于 4.2.1 的 App 也不是想用就能用的。</p>
</blockquote>
<p>建议大家在 Google Analytics 平台查看自己应用在 4.2.1 以下版本用户量多少，评估是否可以升上去。</p>
<p><strong>如何转换</strong></p>
<blockquote>
<p>在 AS 里面提供了支持一键转换 WebP 格式功能，需要转换的图片右键 &ndash;&gt; Convert to Webp&hellip;</p>
</blockquote>
<p>

<div class="fancybox">
<a data-fancybox="demo" href="/images/2019/09/04.png">
<img src="/images/2019/09/04.png" alt="image"  />
</a>
</div>

</p>
<p>当然你也可以外部工具对图片进行 WebP 格式转换，推荐使用 <a href="https://squoosh.app/">Squoosh</a>。</p>
<h3 id="适配多套分辨率图片"><strong>适配多套分辨率图片</strong></h3>
<p>根据应用用户量使用的屏幕分辨率数据来，来决定你最终使用哪几套图片，从数据上来看目前设备分辨率大多数都是 1080x2094 和 1080x1920，因此这里我只用了 <code>xxhdpi</code> 和 <code>xxxhdpi</code> 两套资源。</p>
<p>下面是各套资源对应设备的分辨率以及像素信息表格：</p>
<table>
<thead>
<tr>
<th>类型</th>
<th>分辨率(px)</th>
<th>屏幕像素密度(dpi)</th>
</tr>
</thead>
<tbody>
<tr>
<td>ldpi</td>
<td>200x320</td>
<td>120</td>
</tr>
<tr>
<td>mdpi</td>
<td>320x480</td>
<td>160</td>
</tr>
<tr>
<td>hdpi</td>
<td>480x800</td>
<td>240</td>
</tr>
<tr>
<td>xhdpi</td>
<td>720x1280</td>
<td>320</td>
</tr>
<tr>
<td>xxhdpi</td>
<td>960x1600</td>
<td>480</td>
</tr>
<tr>
<td>xxxhdpi</td>
<td>1440x2560</td>
<td>640</td>
</tr>
</tbody>
</table>
<p>数据来自：http://iconhandbook.co.uk/reference/chart/android/</p>
<h2 id="apk-瘦身之代码混淆">Apk 瘦身之代码混淆</h2>
<p>开启代码混淆能将代码中的类、字段、方法的名字改为简短、无意义的名字；移除未使用的类、字段、方法、属性等，因此可以减少 Dex 文件的大小。</p>
<div class="highlight"><pre class="chroma"><code class="language-fallback" data-lang="fallback">android {
    buildTypes {
        release {
            // 开启混淆
            minifyEnabled true
            proguardFiles getDefaultProguardFile(‘proguard-android.txt&#39;),
                    &#39;proguard-rules.pro&#39;
        }
    }
    ...
}
</code></pre></div><h2 id="apk-瘦身之开启-shrinkresources">Apk 瘦身之开启 shrinkResources</h2>
<p>开启 shrinkResources 可以移除无用资源，依赖于 minifyEnabled，必须和 minifyEnabled 一起用，就是打开 shrinkResources 也必须打开 minifyEnabled。</p>
<div class="highlight"><pre class="chroma"><code class="language-fallback" data-lang="fallback">android {
    buildTypes {
        release {
            // 开启混淆
            minifyEnabled true
            // 移除无用资源
            shrinkResources true
            
            proguardFiles getDefaultProguardFile(‘proguard-android.txt&#39;),
                    &#39;proguard-rules.pro&#39;
        }
    }
    ...
}
</code></pre></div><p>这里开启我发现有些未使用的资源无法移除的，可能是一些没用的代码对一些资源进行引用，导致没有移除，建议大家还是使用 <code>Remove Unused Resources</code> 来检查。</p>
<h2 id="apk-瘦身之配置-resconfigs">Apk 瘦身之配置 resConfigs</h2>
<p>配置应用使用哪些资源，例如你的应用只支持英语和阿拉伯语，那么可以这样配置：</p>
<div class="highlight"><pre class="chroma"><code class="language-fallback" data-lang="fallback">android {
    defaultConfig {
        ...
        // 语言资源，只支持英语和阿拉伯语
        resConfigs &#34;en&#34;,&#34;ar&#34;
        // 图片资源，只支持xhdpi和xxhdpi屏幕的资源
        resConfigs &#34;xxhdpi&#34;,&#34;xxxhdpi&#34; 
    }
}
</code></pre></div><h1 id="最后">最后</h1>
<p>看下瘦身后的效果，比之前减少了 2.5MB。</p>
<p>

<div class="fancybox">
<a data-fancybox="demo" href="/images/2019/09/05.png">
<img src="/images/2019/09/05.png" alt="image"  />
</a>
</div>

</p>
<h1 id="参考链接">参考链接</h1>
<p>更多瘦身优化的方法：</p>
<p><a href="https://juejin.im/post/59113583ac502e450280e5f3#heading-25">https://juejin.im/post/59113583ac502e450280e5f3#heading-25</a></p>
</div>
                    <div class="post_footer">
                        
                        <div class="meta">
                            <div class="info">
                                <span class="field tags">
                                    <i class="ri-stack-line"></i>
                                    
                                    <a href="https://gojun.me/tags/android/">Android</a>
                                    
                                </span>
                            </div>
                        </div>
                        
                    </div>
                </div>
                
                
                <div class="doc_comments"></div>
                
            </div>
        </div>
    </div>
    <a id="back_to_top" href="#" class="back_to_top"><i class="ri-arrow-up-s-line"></i></a>
    <footer class="footer">
    <div class="footer_slogan">
        <span></span>
    </div>
</footer>
    <script src="https://gojun.me/js/jquery-3.5.1.min.js"></script>
<link href="https://gojun.me/css/fancybox.min.css" rel="stylesheet">
<script src="https://gojun.me/js/fancybox.min.js"></script>
<script src="https://gojun.me/js/zozo.js"></script>


<script type="text/javascript" async
    src="https://cdn.bootcss.com/mathjax/2.7.5/MathJax.js?config=TeX-AMS-MML_HTMLorMML">
        MathJax.Hub.Config({
            tex2jax: {
                inlineMath: [['$', '$'], ['\\(', '\\)']],
                displayMath: [['$$', '$$'], ['\[\[', '\]\]']],
                processEscapes: true,
                processEnvironments: true,
                skipTags: ['script', 'noscript', 'style', 'textarea', 'pre'],
                TeX: {
                    equationNumbers: { autoNumber: "AMS" },
                    extensions: ["AMSmath.js", "AMSsymbols.js"]
                }
            }
        });

        MathJax.Hub.Queue(function () {
            
            
            
            var all = MathJax.Hub.getAllJax(), i;
            for (i = 0; i < all.length; i += 1) {
                all[i].SourceElement().parentNode.className += ' has-jax';
            }
        });
    </script>

<style>
    code.has-jax {
        font: inherit;
        font-size: 100%;
        background: inherit;
        border: inherit;
        color: #515151;
    }
</style>



<script type="application/javascript">
var doNotTrack = false;
if (!doNotTrack) {
	window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date;
	ga('create', 'UA-142037913-1', 'auto');
	
	ga('send', 'pageview');
}
</script>
<script async src='https://www.google-analytics.com/analytics.js'></script>

</body>

</html>